﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Ormon.HostLinkLib.HostLinkBase
{
    internal class HostLinkCore
    {
        /// <summary>
        /// 通过命令帧计算FCS异或校验码并加上结束符
        /// </summary>
        /// <param name="CommandFrame">命令帧</param>
        /// <returns>4位字节数组，包含FCS校验码与结束符</returns>
        public static List<byte> HostLinkEndCode(List<byte> CommandFrame)
        {
            try
            {
                List<byte> EndCode = new List<byte>();
                short FCSNum = HostLinkFCS(CommandFrame);

                string HexString = FCSNum.ToString("X2");

                EndCode.AddRange(Encoding.ASCII.GetBytes(HexString));
                EndCode.AddRange(new List<byte> { 0x2A, 0x0D });
                return EndCode;
            }
            catch (Exception)
            {
                throw;
            }
        }

        
        /// <summary>
        /// 对字节数组进行异或运算得到数值
        /// </summary>
        /// <param name="CommandFrame">命令帧</param>
        /// <returns>异或运算结果(short类型)</returns>
        public static short HostLinkFCS(List<byte> CommandFrame)
        {
            try
            {
                short CheckNum = 0;
                foreach (byte FrameNum in CommandFrame)
                {
                    CheckNum ^= FrameNum;
                }
                return CheckNum;
            }
            catch (Exception)
            {
                throw;
            }
        }


        /// <summary>
        /// 检查回复帧是否完整
        /// </summary>
        /// <param name="frame">回复帧</param>
        /// <returns>完整结尾：返回True；不完整：返回False</returns>
        private static bool CheckResponseFrame(List<byte> frame)
        {
            if (frame.Count > 0 && frame[frame.Count - 1] == (byte)0x0D)
            {
                return true;
            }
            else
            {
                return false;
            }
        }




        /// <summary>
        /// HostLink报文发送与接收代码
        /// </summary>
        /// <param name="serialPort">串口实例</param>
        /// <param name="CommandFrame">命令帧</param>
        /// <returns>回复帧</returns>
        public static List<byte> HostLinkCommCore(SerialPort serialPort, List<byte> CommandFrame)
        {
            try
            {
                List<byte> ResponseFrame = new List<byte>();

                serialPort.ReadTimeout = 2000;
                serialPort.WriteTimeout = 2000;

                //发送报文
                serialPort.Write(CommandFrame.ToArray(), 0, CommandFrame.Count);

                //循环读取数据
                while (serialPort.IsOpen)
                {
                    if (serialPort.BytesToRead > 0)
                    {
                        byte[] buffer = new byte[serialPort.BytesToRead];
                        serialPort.Read(buffer, 0, buffer.Length);

                        ResponseFrame.AddRange(buffer);

                        if (CheckResponseFrame(ResponseFrame))
                        {
                            return ResponseFrame;
                        }
                    }
                }

                //如果超时就返回null
                return null;
            }
            catch (Exception)
            {
                throw;
            }
        }




        /// <summary>
        /// HostLink报文发送与接收代码（异步方法）
        /// </summary>
        /// <param name="serialPort">串口实例</param>
        /// <param name="CommandFrame">命令帧</param>
        /// <returns>回复帧</returns>
        public static async Task<List<byte>> HostLinkCommCoreAsync(SerialPort serialPort, List<byte> CommandFrame)
        {
            try
            {
                List<byte> ResponseFrame = new List<byte>();

                serialPort.ReadTimeout = 2000;
                serialPort.WriteTimeout = 2000;

                //发送报文
                await serialPort.BaseStream.WriteAsync(CommandFrame.ToArray(), 0, CommandFrame.Count);

                //循环读取数据
                while (serialPort.IsOpen)
                {
                    if (serialPort.BytesToRead > 0)
                    {
                        byte[] buffer = new byte[serialPort.BytesToRead];
                        await serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length);
                        
                        ResponseFrame.AddRange(buffer);

                        if (CheckResponseFrame(ResponseFrame))
                        {
                            return ResponseFrame;
                        }
                    }
                }

                //如果超时就返回null
                return null;
            }
            catch (Exception)
            {
                throw;
            }
        }


    }
}
